/**
 * @Description: spin加载，支持不同的spin方式
 * @Author BPF
 * @create 2021/10/6 14:23
 */
import './spin.scss'
import { domUtils, isBoolean, isObject, uuid } from '@bianpengfei/utils'

let uid = 1

export default {
  name: 'spin',

  /**
   * 传入的属性props
   */
  props: {
    id: undefined,
    loading: true,
    type: 'dot', // 可选值 dot rect circle circular
    size: 'default', // 可选值 default small large
    showLoadingText: true, // 是否展示loading 文字
    loadingText: '加载中...', // loading文字内容
    delay: 20 // 延迟渲染，防止闪烁现象
  },

  /**
   * 生成要插入的html
   * @param props
   * @returns {string}
   */
  adjacentHTML(props) {
    return `
           <div class="spin-popper" data-type="spin"  data-spin-id="${props.id}">
           ${
             props.type == 'dot'
               ? '<div class="spinner-dot spinner-dot--' +
                 (props.size || 'default') +
                 '"><i></i><i></i><i></i><i></i></div>'
               : ''
           }
            ${
              props.type == 'rect'
                ? '<div class="spinner-rect spinner-rect--' +
                  (props.size || 'default') +
                  '"><div class="cube1"></div><div class="cube2"></div></div>'
                : ''
            }

              ${
                props.type == 'circle'
                  ? '<svg viewBox="25 25 50 50" class="spinner-circle spinner-circle--' +
                    (props.size || 'default') +
                    '"> <circle cx="50" cy="50" r="20" fill="none" class="path-background path"></circle>' +
                    '<circle cx="50" cy="50" r="20" fill="none" class="path-loading path"></circle></svg>'
                  : ''
              }
              
                ${
                  props.type == 'circular'
                    ? '<svg viewBox="25 25 50 50" class="spinner-circular spinner-circular--' +
                      (props.size || 'default') +
                      '"> <circle cx="50" cy="50" r="20" fill="none" class="path"></circle></svg>'
                    : ''
                }

             ${
               props.showLoadingText
                 ? '<div class="loading__text loading__text--' +
                   (props.size || 'default') +
                   '">' +
                   props.loadingText +
                   '</div>'
                 : ''
             }
           </div>
           <div class="spin-popper--mask" data-type="spin" data-spin-id="${props.id}"></div>
           `
  },

  /**
   * 更新dom节点
   * @param el 当前节点
   * @param props props属性值
   */
  updateDomNode(el, props) {
    const spinPopperEls = el.querySelectorAll(`.spin-popper[data-spin-id="${props.id}"]`) // popper
    const spinPopperMaskEls = el.querySelectorAll(`.spin-popper--mask[data-spin-id="${props.id}"]`) // mask遮盖层

    if (props.loading) {
      spinPopperEls.forEach((node) => {
        node.remove()
      })
      spinPopperMaskEls.forEach((node) => {
        node.remove()
      })
      el.insertAdjacentHTML('beforeend', this.adjacentHTML(props))
    } else {
      spinPopperEls.forEach((node, idx) => {
        if (idx == 0) {
          domUtils.setStyle(node, 'opacity', 0)
          setTimeout(() => {
            node.dataset.type == 'spin' && node.remove()
          }, 300)
        } else {
          node.remove()
        }
      })

      spinPopperMaskEls.forEach((node, idx) => {
        if (idx == 0) {
          domUtils.setStyle(node, 'opacity', 0)
          setTimeout(() => {
            node.dataset.type == 'spin' && node.remove()
          }, 300)
        } else {
          node.remove()
        }
      })
    }
  },

  mergeBindingVal(binding = {}) {
    let props = {}
    if (isBoolean(binding.value)) {
      props = {
        ...this.props,
        ...binding.modifiers,
        loading: binding.value
      }
    } else if (isObject(binding.value)) {
      props = {
        ...this.props,
        ...binding.modifiers,
        ...binding.value
      }
    }
    return props
  },

  /**
   * 安装指令
   * @param app
   */
  install(app) {
    app.directive(this.name, {
      bind: (el, binding, vnode) => {
        const props = this.mergeBindingVal(binding)
        props.id = 'x_' + uuid().slice(0, 6) + '_' + ++uid
        el.dataset.spinId = props.id
        // 防止闪烁
        setTimeout(() => {
          domUtils.addClasses(el, ['v-spin-wrap'])
          this.updateDomNode(el, props)
        }, props.delay)
      },

      update: (el, binding, vnode) => {
        if (JSON.stringify(binding.oldValue) === JSON.stringify(binding.value)) return
        const props = this.mergeBindingVal(binding)
        props.id ||= el.dataset.spinId
        this.updateDomNode(el, props)
      }
    })
  }
}
